#include "Color.h"

const Color Color::WHITE(0xFFFFFF);
const Color Color::LIGHT_GRAY(0xC0C0C0);
const Color Color::GRAY(0x808080);
const Color Color::DARK_GRAY(0x404040);
const Color Color::BLACK(0x000000);
const Color Color::RED(0xFF0000);
const Color Color::GREEN(0x00FF00);
const Color Color::BLUE(0x0000FF);
const Color Color::CYAN(0x00FFFF);
const Color Color::MAGENTA(0xFF00FF);
const Color Color::YELLOW(0xFFFF00);
const Color Color::PINK(0xFFA0A0);
const Color Color::COTTON_CANDY(0xFFC0E0);
const Color Color::ORANGE(0xFFA000);
const Color Color::VIOLET(0xA000FF);
const Color Color::PURPLE(0x6000A0);
const Color Color::LIME(0xA0FF00);
const Color Color::BEIGE(0xF0F0E0);
const Color Color::INDIGO(0x4F69C6);
const Color Color::BROWN(0x964B00);
const Color Color::DARK_BROWN(0x5C2E01);
const Color Color::GOLD(0xFFD700);

static const int ORDER_ALPHA	= 3;
static const int ORDER_BLUE		= 0;
static const int ORDER_GREEN	= 1;
static const int ORDER_RED		= 2;

static const int MASK_ALPHA		= 8 * ORDER_ALPHA;
static const int MASK_BLUE		= 8 * ORDER_BLUE;
static const int MASK_GREEN		= 8 * ORDER_GREEN;
static const int MASK_RED		= 8 * ORDER_RED;

static const int UNMASK_ALPHA	= 0xFF << MASK_ALPHA;
static const int UNMASK_BLUE	= 0xFF << MASK_BLUE;
static const int UNMASK_GREEN	= 0xFF << MASK_GREEN;
static const int UNMASK_RED		= 0xFF << MASK_RED;

Color::Color(double red, double green, double blue, double alpha) {
    this->red = (red < 1.0) ? ((red > 0.0) ? red : 0.0) : 1.0;
    this->green = (green < 1.0) ? ((green > 0.0) ? green : 0.0) : 1.0;
    this->blue = (blue < 1.0) ? ((blue > 0.0) ? blue : 0.0) : 1.0;
    this->alpha = (alpha < 1.0) ? ((alpha > 0.0) ? alpha : 0.0) : 1.0;
}

Color::Color(double red, double green, double blue) : Color(red, green, blue, 1.0) {
}

Color::Color(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha) : red(red / 255.0),
                        green(green / 255.0), blue(blue / 255.0), alpha(alpha / 255.0) {
}

Color::Color(int codedColor) : Color(GLbyte((codedColor & UNMASK_RED) >> MASK_RED),
                                     GLbyte((codedColor & UNMASK_GREEN) >> MASK_GREEN),
                                     GLbyte((codedColor & UNMASK_BLUE) >> MASK_BLUE),
                                     GLbyte(((codedColor & UNMASK_ALPHA) == 0) ? 0xFF :
                                            ((codedColor & UNMASK_ALPHA) >> MASK_ALPHA))) {
}

void Color::bind() {
    glColor4d(this->red, this->green, this->blue, this->alpha);
}

double Color::getRed() {
    return this->red;
}

double Color::getGreen() {
    return this->green;
}

double Color::getBlue() {
    return this->blue;
}

double Color::getAlpha() {
    return this->alpha;
}

GLbyte Color::getByteRed() {
    return GLbyte(this->red * 255.0);
}

GLbyte Color::getByteGreen() {
    return GLbyte(this->green * 255.0);
}

GLbyte Color::getByteBlue() {
    return GLbyte(this->blue * 255.0);
}

GLbyte Color::getByteAlpha() {
    return GLbyte(this->alpha * 255.0);
}

int Color::getCodedInteger() {
    int codedColor = (this->getByteAlpha() << MASK_ALPHA);
    codedColor |= (this->getByteBlue() << MASK_BLUE);
    codedColor |= (this->getByteGreen() << MASK_GREEN);
    codedColor |= (this->getByteRed() << MASK_RED);
    return codedColor;
}

Color Color::interpolate(const Color &op2, const double alpha) {
    return Color(((1 - alpha) * this->red) + (alpha * op2.red),
                 ((1 - alpha) * this->green) + (alpha * op2.green),
                 ((1 - alpha) * this->blue) + (alpha * op2.blue),
                 ((1 - alpha) * this->alpha) + (alpha * op2.alpha));
}
